<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<head>
    <title>Penlight Documentation</title>
    <link rel="stylesheet" href="../ldoc.css" type="text/css" />
</head>
<body>

<div id="container">

<div id="product">
	<div id="product_logo"></div>
	<div id="product_name"><big><b></b></big></div>
	<div id="product_description"></div>
</div> <!-- id="product" -->


<div id="main">


<!-- Menu -->

<div id="navigation">
<br/>
<h1>Penlight</h1>

<ul>
  <li><a href="../index.html">Index</a></li>
</ul>



<h2>Examples</h2>
<ul>
  <li><a href="../examples/seesubst.lua.html">seesubst.lua</a></li>
  <li><a href="../examples/sipscan.lua.html">sipscan.lua</a></li>
  <li><a href="../examples/symbols.lua.html">symbols.lua</a></li>
  <li><a href="../examples/test-cmp.lua.html">test-cmp.lua</a></li>
  <li><strong>test-data.lua</strong></li>
  <li><a href="../examples/test-listcallbacks.lua.html">test-listcallbacks.lua</a></li>
  <li><a href="../examples/test-pretty.lua.html">test-pretty.lua</a></li>
  <li><a href="../examples/test-symbols.lua.html">test-symbols.lua</a></li>
  <li><a href="../examples/testapp.lua.html">testapp.lua</a></li>
  <li><a href="../examples/testclone.lua.html">testclone.lua</a></li>
  <li><a href="../examples/testconfig.lua.html">testconfig.lua</a></li>
  <li><a href="../examples/testglobal.lua.html">testglobal.lua</a></li>
  <li><a href="../examples/testinputfields.lua.html">testinputfields.lua</a></li>
  <li><a href="../examples/testinputfields2.lua.html">testinputfields2.lua</a></li>
  <li><a href="../examples/testxml.lua.html">testxml.lua</a></li>
  <li><a href="../examples/which.lua.html">which.lua</a></li>
</ul>
<h2>Modules</h2>
<ul>
  <li><a href="../modules/pl.html">pl</a></li>
  <li><a href="../modules/pl.Date.html">pl.Date</a></li>
  <li><a href="../modules/pl.List.html">pl.List</a></li>
  <li><a href="../modules/pl.Map.html">pl.Map</a></li>
  <li><a href="../modules/pl.MultiMap.html">pl.MultiMap</a></li>
  <li><a href="../modules/pl.OrderedMap.html">pl.OrderedMap</a></li>
  <li><a href="../modules/pl.Set.html">pl.Set</a></li>
  <li><a href="../modules/pl.app.html">pl.app</a></li>
  <li><a href="../modules/pl.array2d.html">pl.array2d</a></li>
  <li><a href="../modules/pl.class.html">pl.class</a></li>
  <li><a href="../modules/pl.comprehension.html">pl.comprehension</a></li>
  <li><a href="../modules/pl.config.html">pl.config</a></li>
  <li><a href="../modules/pl.data.html">pl.data</a></li>
  <li><a href="../modules/pl.dir.html">pl.dir</a></li>
  <li><a href="../modules/pl.file.html">pl.file</a></li>
  <li><a href="../modules/pl.func.html">pl.func</a></li>
  <li><a href="../modules/pl.input.html">pl.input</a></li>
  <li><a href="../modules/pl.lapp.html">pl.lapp</a></li>
  <li><a href="../modules/pl.lexer.html">pl.lexer</a></li>
  <li><a href="../modules/pl.luabalanced.html">pl.luabalanced</a></li>
  <li><a href="../modules/pl.operator.html">pl.operator</a></li>
  <li><a href="../modules/pl.path.html">pl.path</a></li>
  <li><a href="../modules/pl.permute.html">pl.permute</a></li>
  <li><a href="../modules/pl.pretty.html">pl.pretty</a></li>
  <li><a href="../modules/pl.seq.html">pl.seq</a></li>
  <li><a href="../modules/pl.sip.html">pl.sip</a></li>
  <li><a href="../modules/pl.strict.html">pl.strict</a></li>
  <li><a href="../modules/pl.stringio.html">pl.stringio</a></li>
  <li><a href="../modules/pl.stringx.html">pl.stringx</a></li>
  <li><a href="../modules/pl.tablex.html">pl.tablex</a></li>
  <li><a href="../modules/pl.template.html">pl.template</a></li>
  <li><a href="../modules/pl.test.html">pl.test</a></li>
  <li><a href="../modules/pl.text.html">pl.text</a></li>
  <li><a href="../modules/pl.utils.html">pl.utils</a></li>
  <li><a href="../modules/pl.xml.html">pl.xml</a></li>
</ul>
<h2>Topics</h2>
<ul>
  <li><a href="../topics/01-introduction.md.html">01-introduction.md</a></li>
  <li><a href="../topics/02-arrays.md.html">02-arrays.md</a></li>
  <li><a href="../topics/03-strings.md.html">03-strings.md</a></li>
  <li><a href="../topics/04-paths.md.html">04-paths.md</a></li>
  <li><a href="../topics/05-dates.md.html">05-dates.md</a></li>
  <li><a href="../topics/06-data.md.html">06-data.md</a></li>
  <li><a href="../topics/07-functional.md.html">07-functional.md</a></li>
  <li><a href="../topics/08-additional.md.html">08-additional.md</a></li>
  <li><a href="../topics/09-discussion.md.html">09-discussion.md</a></li>
</ul>

</div>

<div id="content">

<h1>Example <code>test-data.lua</code></h1>

    <pre>
<span class="comment">--_DEBUG=true
</span>data = <span class="global">require</span> <span class="string">'pl.data'</span>
List = <span class="global">require</span> <span class="string">'pl.List'</span>
array = <span class="global">require</span> <span class="string">'pl.array2d'</span>
seq = <span class="global">require</span> <span class="string">'pl.seq'</span>
utils = <span class="global">require</span> <span class="string">'pl.utils'</span>
stringio = <span class="global">require</span> <span class="string">'pl.stringio'</span>
open = stringio. open
asserteq = <span class="global">require</span> <span class="string">'pl.test'</span> . asserteq
T = <span class="global">require</span> <span class="string">'pl.test'</span>. tuple

<span class="comment">-- tab-separated data, explicit column names
</span>t1f = open <span class="string">[[
EventID	Magnitude	LocationX	LocationY	LocationZ	LocationError	EventDate	DataFile
981124001	2.0	18988.4	10047.1	4149.7	33.8	24/11/1998 11:18:05	981124DF.AAB
981125001	0.8	19104.0	9970.4	5088.7	3.0	25/11/1998 05:44:54	981125DF.AAB
981127003	0.5	19012.5	9946.9	3831.2	46.0	27/11/1998 17:15:17	981127DF.AAD
981127005	0.6	18676.4	10606.2	3761.9	4.4	27/11/1998 17:46:36	981127DF.AAF
981127006	0.2	19109.9	9716.5	3612.0	11.8	27/11/1998 19:29:51	981127DF.AAG
]]</span>

t1 = data.read (t1f)
<span class="comment">-- column_by_name returns a List
</span>asserteq(t1:column_by_name <span class="string">'Magnitude'</span>,List{<span class="number">2</span>,<span class="number">0.8</span>,<span class="number">0.5</span>,<span class="number">0.6</span>,<span class="number">0.2</span>})
<span class="comment">-- can use array.column as well
</span>asserteq(array.column(t1,<span class="number">2</span>),{<span class="number">2</span>,<span class="number">0.8</span>,<span class="number">0.5</span>,<span class="number">0.6</span>,<span class="number">0.2</span>})

<span class="comment">-- only numerical columns (deduced from first data row) are converted by default
</span><span class="comment">-- can look up indices in the list fieldnames.
</span>EDI = t1.fieldnames:index <span class="string">'EventDate'</span>
<span class="global">assert</span>(<span class="global">type</span>(t1[<span class="number">1</span>][EDI]) == <span class="string">'string'</span>)

<span class="comment">-- select method returns a sequence, in this case single-valued.
</span><span class="comment">-- (Note that seq.copy returns a List)
</span>asserteq(seq(t1:<span class="global">select</span> <span class="string">'LocationX where Magnitude &gt; 0.5'</span>):copy(),List{<span class="number">18988.4</span>,<span class="number">19104</span>,<span class="number">18676.4</span>})

<span class="comment">--[[
--a common select usage pattern:
for event,mag in t1:select 'EventID,Magnitude sort by Magnitude desc' do
    print(event,mag)
end
--]]</span>

<span class="comment">-- space-separated, but with last field containing spaces.
</span>t2f = open <span class="string">[[
USER PID %MEM %CPU COMMAND
sdonovan 2333  0.3 0.1 background --n=2
root 2332  0.4  0.2 fred --start=yes
root 2338  0.2  0.1 backyard-process
]]</span>

t2,err = data.read(t2f,{last_field_collect=<span class="keyword">true</span>})
<span class="keyword">if</span> <span class="keyword">not</span> t2 <span class="keyword">then</span> <span class="keyword">return</span> <span class="global">print</span> (err) <span class="keyword">end</span>

<span class="comment">-- the last_field_collect option is useful with space-delimited data where the last
</span><span class="comment">-- field may contain spaces. Otherwise, a record count mismatch should be an error!
</span>lt2 = List(t2[<span class="number">2</span>])
asserteq(lt2:join <span class="string">','</span>,<span class="string">'root,2332,0.4,0.2,fred --start=yes'</span>)

<span class="comment">-- fieldnames are converted into valid identifiers by substituting _
</span><span class="comment">-- (we do this to make select queries parseable by Lua)
</span>asserteq(t2.fieldnames,List{<span class="string">'USER'</span>,<span class="string">'PID'</span>,<span class="string">'_MEM'</span>,<span class="string">'_CPU'</span>,<span class="string">'COMMAND'</span>})

<span class="comment">-- select queries are NOT SQL so remember to use == ! (and no 'between' operator, sorry)
</span><span class="comment">--s,err = t2:select('_MEM where USER="root"')
</span><span class="comment">--assert(err == [[[string "tmp"]:9: unexpected symbol near '=']])
</span>
s = t2:<span class="global">select</span>(<span class="string">'_MEM where USER=="root"'</span>)
<span class="global">assert</span>(s() == <span class="number">0.4</span>)
<span class="global">assert</span>(s() == <span class="number">0.2</span>)
<span class="global">assert</span>(s() == <span class="keyword">nil</span>)

<span class="comment">-- CSV, Excel style
</span>t3f = open <span class="string">[[
Department Name,Employee ID,Project,Hours Booked
sales,1231,overhead,4
sales,1255,overhead,3
engineering,1501,development,5
engineering,1501,maintenance,3
engineering,1433,maintenance,10
]]</span>

t3 = data.read(t3f)

<span class="comment">-- a common operation is to select using a given list of columns, and each row
</span><span class="comment">-- on some explicit condition. The select() method can take a table with these
</span><span class="comment">-- parameters
</span>keepcols = {<span class="string">'Employee_ID'</span>,<span class="string">'Hours_Booked'</span>}

q = t3:<span class="global">select</span> { fields = keepcols,
    where = <span class="keyword">function</span>(row) <span class="keyword">return</span> row[<span class="number">1</span>]==<span class="string">'engineering'</span> <span class="keyword">end</span>
    }

asserteq(seq.copy2(q),{{<span class="number">1501</span>,<span class="number">5</span>},{<span class="number">1501</span>,<span class="number">3</span>},{<span class="number">1433</span>,<span class="number">10</span>}})

<span class="comment">-- another pattern is doing a select to restrict rows &amp; columns, process some
</span><span class="comment">-- fields and write out the modified rows.
</span>
utils.import <span class="string">'pl.func'</span>

outf = stringio.create()

names = {[<span class="number">1501</span>]=<span class="string">'don'</span>,[<span class="number">1433</span>]=<span class="string">'dilbert'</span>}

t3:write_row (outf,{<span class="string">'Employee'</span>,<span class="string">'Hours_Booked'</span>})
q = t3:select_row {fields=keepcols,where=Eq(_1[<span class="number">1</span>],<span class="string">'engineering'</span>)}
<span class="keyword">for</span> row <span class="keyword">in</span> q <span class="keyword">do</span>
    row[<span class="number">1</span>] = names[row[<span class="number">1</span>]]
    t3:write_row(outf,row)
<span class="keyword">end</span>

asserteq(outf:value(),
<span class="string">[[
Employee,Hours_Booked
don,5
don,3
dilbert,10
]]</span>)

<span class="comment">-- data may not always have column headers. When creating a data object
</span><span class="comment">-- from a two-dimensional array, must specify the fieldnames, as a list or a string.
</span><span class="comment">-- The delimiter is deduced from the fieldname string, so a string just containing
</span><span class="comment">-- the delimiter will set it,  and the fieldnames will be empty.
</span><span class="keyword">local</span> dat = List()
<span class="keyword">local</span> row = List.range(<span class="number">1</span>,<span class="number">10</span>)
<span class="keyword">for</span> i = <span class="number">1</span>,<span class="number">10</span> <span class="keyword">do</span>
    dat:append(row:map(<span class="string">'*'</span>,i))
<span class="keyword">end</span>
dat = data.new(dat,<span class="string">','</span>)
<span class="keyword">local</span> out = stringio.create()
dat:write(out,<span class="string">','</span>)
asserteq(out:value(), <span class="string">[[
1,2,3,4,5,6,7,8,9,10
2,4,6,8,10,12,14,16,18,20
3,6,9,12,15,18,21,24,27,30
4,8,12,16,20,24,28,32,36,40
5,10,15,20,25,30,35,40,45,50
6,12,18,24,30,36,42,48,54,60
7,14,21,28,35,42,49,56,63,70
8,16,24,32,40,48,56,64,72,80
9,18,27,36,45,54,63,72,81,90
10,20,30,40,50,60,70,80,90,100
]]</span>)

<span class="comment">-- you can always use numerical field indices, AWK-style;
</span><span class="comment">-- note how the copy_select method gives you a data object instead of an
</span><span class="comment">-- iterator over the fields
</span><span class="keyword">local</span> res = dat:copy_select <span class="string">'$1,$3 where $1 &gt; 5'</span>
<span class="keyword">local</span> L = List
asserteq(L(res),L{
    L{<span class="number">6</span>, <span class="number">18</span>},
    L{<span class="number">7</span>,<span class="number">21</span>},
    L{<span class="number">8</span>,<span class="number">24</span>},
    L{<span class="number">9</span>,<span class="number">27</span>},
    L{<span class="number">10</span>,<span class="number">30</span>},
})

<span class="comment">-- the column_by_name method may take a fieldname or an index
</span>asserteq(dat:column_by_name(<span class="number">2</span>), L{<span class="number">2</span>,<span class="number">4</span>,<span class="number">6</span>,<span class="number">8</span>,<span class="number">10</span>,<span class="number">12</span>,<span class="number">14</span>,<span class="number">16</span>,<span class="number">18</span>,<span class="number">20</span>})

<span class="comment">-- the field list may contain expressions or even constants
</span><span class="keyword">local</span> q = dat:<span class="global">select</span> <span class="string">'$3,2*$4 where $1 == 8'</span>
asserteq(T(q()),T(<span class="number">24</span>,<span class="number">64</span>))

dat = data.read(open <span class="string">[[
1.0 0.1
0.2 1.3
]]</span>)

<span class="comment">-- if a method cannot be found, then we look up in array2d
</span><span class="comment">-- array2d.flatten(t) makes a 1D list out of a 2D array,
</span><span class="comment">-- and then List.minmax() gets the extrema.
</span>
asserteq(T(dat:flatten():minmax()),T(<span class="number">0.1</span>,<span class="number">1.3</span>))

</div> <!-- id="content" -->
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.2</a></i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>
</html>
